//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#ifndef _PCI_H
#define _PCI_H

typedef enum
{
    PCIProbe1 = 0,
    PCIProbe2,
    PCIForceConfig1,
    PCIForceConfig2
} PciProbeType;

typedef UInt16 IO_PORT;

inline UInt32 IOSpaceReadInt32(IO_PORT port)
{
    return Inl(port);
}

inline void IOSpaceWriteInt32(IO_PORT port, UInt32 Value)
{
    Outl(port, Value);
}

inline UInt16 IOSpaceReadInt16(IO_PORT port)
{
    return Inw(port);
}

inline void IOSpaceWriteInt16(IO_PORT port, UInt16 Value)
{
    Outw(port, Value);
}

inline UInt8 IOSpaceReadInt8(IO_PORT port)
{
    return Inb(port);
}

inline void IOSpaceWriteInt8(IO_PORT port, UInt8 Value)
{
    Outb(port, Value);
}

typedef struct pci_config_reg
{
    /* start of official PCI config space header */
    union
    {
        UInt32 device_vendor;
        struct
        {
            UInt16 vendor;
            UInt16 device;
        } dv;
    } dv_id;
#define _device_vendor dv_id.device_vendor
#define _vendor dv_id.dv.vendor
#define _device dv_id.dv.device
    union
    {
        UInt32 status_command;
        struct
        {
            UInt16 command;
            UInt16 status;
        } sc;
    } stat_cmd;
#define _status_command stat_cmd.status_command
#define _command stat_cmd.sc.command
#define _status  stat_cmd.sc.status
    union
    {
        UInt32 class_revision;
        struct
        {
            UInt8 rev_id;
            UInt8 prog_if;
            UInt8 sub_class;
            UInt8 base_class;
        } cr;
    } class_rev;
#define _class_revision class_rev.class_revision
#define _rev_id     class_rev.cr.rev_id
#define _prog_if    class_rev.cr.prog_if
#define _sub_class  class_rev.cr.sub_class
#define _base_class class_rev.cr.base_class
    union
    {
        UInt32 bist_header_latency_cache;
        struct
        {
            UInt8 cache_line_size;
            UInt8 latency_timer;
            UInt8 header_type;
            UInt8 bist;
        } bhlc;
    } bhlc;
#define _bist_header_latency_cache bhlc.bist_header_latency_cache
#define _cache_line_size bhlc.bhlc.cache_line_size
#define _latency_timer   bhlc.bhlc.latency_timer
#define _header_type     bhlc.bhlc.header_type
#define _bist            bhlc.bhlc.bist
    union
    {
        struct
        {
            UInt32 dv_base0;
            UInt32 dv_base1;
            UInt32 dv_base2;
            UInt32 dv_base3;
            UInt32 dv_base4;
            UInt32 dv_base5;
        } dv;
        struct
        {
            UInt32 bg_rsrvd[2];
            UInt8 primary_bus_number;
            UInt8 secondary_bus_number;
            UInt8 subordinate_bus_number;
            UInt8 secondary_latency_timer;
            UInt8 io_base;
            UInt8 io_limit;
            UInt16 secondary_status;
            UInt16 mem_base;
            UInt16 mem_limit;
            UInt16 prefetch_mem_base;
            UInt16 prefetch_mem_limit;
        } bg;
    } bc;
#define    _base0                bc.dv.dv_base0
#define    _base1                bc.dv.dv_base1
#define    _base2                bc.dv.dv_base2
#define    _base3                bc.dv.dv_base3
#define    _base4                bc.dv.dv_base4
#define    _base5                bc.dv.dv_base5
#define    _primary_bus_number        bc.bg.primary_bus_number
#define    _secondary_bus_number        bc.bg.secondary_bus_number
#define    _subordinate_bus_number        bc.bg.subordinate_bus_number
#define    _secondary_latency_timer    bc.bg.secondary_latency_timer
#define _io_base            bc.bg.io_base
#define _io_limit            bc.bg.io_limit
#define _secondary_status        bc.bg.secondary_status
#define _mem_base            bc.bg.mem_base
#define _mem_limit            bc.bg.mem_limit
#define _prefetch_mem_base        bc.bg.prefetch_mem_base
#define _prefetch_mem_limit        bc.bg.prefetch_mem_limit
    UInt32 rsvd1;
    UInt32 rsvd2;
    UInt32 _baserom;
    UInt32 rsvd3;
    UInt32 rsvd4;
    union
    {
        UInt32 max_min_ipin_iline;
        struct
        {
            UInt8 int_line;
            UInt8 int_pin;
            UInt8 min_gnt;
            UInt8 max_lat;
        } mmii;
    } mmii;
#define _max_min_ipin_iline mmii.max_min_ipin_iline
#define _int_line mmii.mmii.int_line
#define _int_pin  mmii.mmii.int_pin
#define _min_gnt  mmii.mmii.min_gnt
#define _max_lat  mmii.mmii.max_lat
    /* I don't know how accurate or standard this is (DHD) */
    union
    {
        UInt32 user_config;
        struct
        {
            UInt8 user_config_0;
            UInt8 user_config_1;
            UInt8 user_config_2;
            UInt8 user_config_3;
        } uc;
    } uc;
#define _user_config uc.user_config
#define _user_config_0 uc.uc.user_config_0
#define _user_config_1 uc.uc.user_config_1
#define _user_config_2 uc.uc.user_config_2
#define _user_config_3 uc.uc.user_config_3
    /* end of official PCI config space header */
#ifdef USE_OLD_PCI_CODE
    UInt32 _pcibusidx;
    UInt32 _pcinumbus;
    UInt32 _pcibuses[16];
    UInt16 _configtype;   /* config type found                   */
    UInt16 _ioaddr;       /* config type 1 - private I/O addr    */
#endif
    UInt32 _bus;
    UInt32 _cardnum;      /* config type 2 - private card number */
    UInt32 _func;         /* function number */
} pciConfigRec, *pciConfigPtr;

typedef union
{
    UInt32 cfg1;
    struct
    {
        UInt8  enable;
        UInt8  forward;
        UInt16 port;
    } cfg2;
    UInt32 tag;
} pciTagRec, *pciTagPtr;

#define PCI_EN 0x80000000

#define MAX_PCI_DEVICES 64

#define PCI_CONFIG1_MAXDEV    32
#define PCI_CONFIG2_MAXDEV    16

/* Registers */
#define PCI_REG_USERCONFIG         0x40
#define PCI_OPTION_REG             0x40

/* PCI Configuration address */
#if defined(_mips)
#define    PCI_MODE1_ADDRESS_REG        (K1BASE + IT8172_BASE + IT_CONFADDR)
#define    PCI_MODE1_DATA_REG           (K1BASE + IT8172_BASE + IT_CONFDATA)
#else
#define    PCI_MODE1_ADDRESS_REG        0xCF8
#define    PCI_MODE1_DATA_REG           0xCFC
#endif

#define    PCI_MODE2_ENABLE_REG        0xCF8

#define    PCI_MODE2_FORWARD_REG        0xCFA

/* Device identification register */
#define PCI_ID_REG            0x00

/* Command and status register */
#define    PCI_CMD_STAT_REG              0x04
#define    PCI_CMD_MASK                  0xffff
#define    PCI_CMD_IO_ENABLE             0x01
#define    PCI_CMD_MEM_ENABLE            0x02
#define    PCI_CMD_MASTER_ENABLE         0x04
#define    PCI_CMD_SPECIAL_ENABLE        0x08
#define    PCI_CMD_INVALIDATE_ENABLE     0x10
#define    PCI_CMD_PALETTE_ENABLE        0x20
#define    PCI_CMD_PARITY_ENABLE         0x40
#define    PCI_CMD_STEPPING_ENABLE       0x80
#define    PCI_CMD_SERR_ENABLE           0x100
#define    PCI_CMD_BACKTOBACK_ENABLE     0x200

/* base classes */
#define PCI_CLASS_REG                  0x08
#define PCI_CLASS_MASK              0xff000000

/* base classes as in _base_class */
#define PCI_CLASS_PREHISTORIC           0x00
#define PCI_CLASS_MASS_STORAGE          0x01
#define PCI_CLASS_NETWORK               0x02
#define PCI_CLASS_DISPLAY               0x03
#define PCI_CLASS_MULTIMEDIA            0x04
#define PCI_CLASS_MEMORY                0x05
#define PCI_CLASS_BRIDGE                0x06
#define PCI_CLASS_UNDEFINED             0xff

/* Sub class */

#define PCI_SUBCLASS_MASK       0x00ff0000

/* Sub classes as in _sub_class */

/* 0x00 prehistoric subclasses */
#define PCI_SUBCLASS_PREHISTORIC_MISC   0x00
#define PCI_SUBCLASS_PREHISTORIC_VGA    0x01

/* 0x01 mass storage subclasses */
#define PCI_SUBCLASS_MASS_STORAGE_SCSI      0x00
#define PCI_SUBCLASS_MASS_STORAGE_IDE       0x01
#define PCI_SUBCLASS_MASS_STORAGE_FLOPPY    0x02
#define PCI_SUBCLASS_MASS_STORAGE_IPI       0x03
#define PCI_SUBCLASS_MASS_STORAGE_MISC      0x80

/* 0x02 network subclasses */
#define PCI_SUBCLASS_NETWORK_ETHERNET       0x00
#define PCI_SUBCLASS_NETWORK_TOKENRING      0x01
#define PCI_SUBCLASS_NETWORK_FDDI           0x02
#define PCI_SUBCLASS_NETWORK_MISC           0x80

/* 0x03 display subclasses */
#define PCI_SUBCLASS_DISPLAY_VGA        0x00
#define PCI_SUBCLASS_DISPLAY_XGA        0x01
#define PCI_SUBCLASS_DISPLAY_MISC       0x80

/* 0x04 multimedia subclasses */
#define PCI_SUBCLASS_MULTIMEDIA_VIDEO   0x00
#define PCI_SUBCLASS_MULTIMEDIA_AUDIO   0x01
#define PCI_SUBCLASS_MULTIMEDIA_MISC    0x80

/* 0x05 memory subclasses */
#define PCI_SUBCLASS_MEMORY_RAM         0x00
#define PCI_SUBCLASS_MEMORY_FLASH       0x01
#define PCI_SUBCLASS_MEMORY_MISC        0x80

/* 0x06 bridge subclasses */
#define PCI_SUBCLASS_BRIDGE_HOST        0x00
#define PCI_SUBCLASS_BRIDGE_ISA         0x01
#define PCI_SUBCLASS_BRIDGE_EISA        0x02
#define PCI_SUBCLASS_BRIDGE_MC          0x03
#define PCI_SUBCLASS_BRIDGE_PCI         0x04
#define PCI_SUBCLASS_BRIDGE_PCMCIA      0x05
#define PCI_SUBCLASS_BRIDGE_MISC        0x80

/* Header */
#define PCI_HEADER_MISC            0x0c
#define PCI_HEADER_MULTIFUNCTION    0x00800000

/* Interrupt configration register */
#define PCI_INTERRUPT_REG        0x3c
#define PCI_INTERRUPT_PIN_MASK          0x0000ff00
#define PCI_INTERRUPT_PIN_EXTRACT(x) \
    ((((x) & PCI_INTERRUPT_PIN_MASK) >> 8) & 0xff)
#define PCI_INTERRUPT_PIN_NONE          0x00
#define PCI_INTERRUPT_PIN_A             0x01
#define PCI_INTERRUPT_PIN_B             0x02
#define PCI_INTERRUPT_PIN_C             0x03
#define PCI_INTERRUPT_PIN_D             0x04

#define PCI_INTERRUPT_LINE_MASK         0x000000ff
#define PCI_INTERRUPT_LINE_EXTRACT(x) \
    ((((x) & PCI_INTERRUPT_LINE_MASK) >> 0) & 0xff)
#define PCI_INTERRUPT_LINE_INSERT(x,v) \
    (((x) & ~PCI_INTERRUPT_LINE_MASK) | ((v) << 0))
/* Mapping registers */
#define PCI_MAP_REG_START               0x10
#define PCI_MAP_REG_END                 0x28
#define PCI_MAP_ROM_REG                 0x30

#define PCI_MAP_MEMORY                  0x00000000
#define PCI_MAP_IO                      0x00000001

#define PCI_MAP_MEMORY_TYPE_32BIT       0x00000000
#define PCI_MAP_MEMORY_TYPE_32BIT_1M    0x00000002
#define PCI_MAP_MEMORY_TYPE_64BIT       0x00000004
#define PCI_MAP_MEMORY_TYPE_MASK        0x00000006
#define PCI_MAP_MEMORY_CACHABLE         0x00000008
#define PCI_MAP_MEMORY_ADDRESS_MASK     0xfffffff0

#define PCI_MAP_IO_ADDRESS_MASK         0xfffffffc

/* PCI-PCI bridge mapping registers */
#define PCI_PCI_BRIDGE_BUS_REG          0x18
#define PCI_PCI_BRIDGE_IO_REG           0x1c
#define PCI_PCI_BRIDGE_MEM_REG          0x20
#define PCI_PCI_BRIDGE_PMEM_REG         0x24

#define PCI_SUBORDINATE_BUS_MASK        0x00ff0000
#define PCI_SECONDARY_BUS_MASK          0x0000ff00
#define PCI_PRIMARY_BUS_MASK            0x000000ff

#define PCI_SUBORDINATE_BUS_EXTRACT(x)  (((x) >> 16) & 0xff)
#define PCI_SECONDARY_BUS_EXTRACT(x)    (((x) >>  8) & 0xff)
#define PCI_PRIMARY_BUS_EXTRACT(x)      (((x)      ) & 0xff)

#define PCI_PRIMARY_BUS_INSERT(x, y) \
    (((x) & ~PCI_PRIMARY_BUS_MASK) | ((y) << 0))
#define PCI_SECONDARY_BUS_INSERT(x, y) \
    (((x) & ~PCI_SECONDARY_BUS_MASK) | ((y) <<  8))
#define PCI_SUBORDINATE_BUS_INSERT(x, y) \
    (((x) & ~PCI_SUBORDINATE_BUS_MASK) | (( y) << 16))

#define PCI_PPB_IOBASE_EXTRACT(x)       (((x) << 8) & 0xFF00)
#define PCI_PPB_IOLIMIT_EXTRACT(x)      (((x) << 0) & 0xFF00)

#define PCI_PPB_MEMBASE_EXTRACT(x)      (((x) << 16) & 0xFFFF0000)
#define PCI_PPB_MEMLIMIT_EXTRACT(x)     (((x) <<  0) & 0xFFFF0000)

EXTERN_C pciConfigPtr *scanpci(
    int
);

EXTERN_C void writepci(
    int,
    int,
    int,
    int,
    int,
    UInt32,
    UInt32
);

EXTERN_C void cleanpci(
    void
);

EXTERN_C pciTagRec pcibusTag(
    UInt8,
    UInt8,
    UInt8
);

EXTERN_C UInt32 pciReadLong(
    pciTagRec,
    UInt32
);

EXTERN_C UInt16 pciReadWord(
    pciTagRec,
    UInt32
);

EXTERN_C UInt8 pciReadByte(
    pciTagRec,
    UInt32
);

EXTERN_C void pcibusWrite(
    pciTagRec,
    UInt32,
    UInt32
);

#define pciWriteLong(tag, addr, data) pcibusWrite(tag, addr, data)

EXTERN_C void pciWriteWord(
    pciTagRec,
    UInt32,
    UInt16
);

EXTERN_C void pciWriteByte(
    pciTagRec,
    UInt32,
    UInt8
);

EXTERN_C pciConfigPtr pci_devp[MAX_PCI_DEVICES + 1];
EXTERN_C PciProbeType PCIFlags;
#endif /* _PCI_H */
